import re
from aiogram import F, types, Router, Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.types import Message, CallbackQuery
from aiogram.filters import CommandStart, Command
from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.context import FSMContext
import database as db
import keyboards as kb
import prs
import uuid

router = Router()
bot = Bot(token="TOKEN")

storage = MemoryStorage()
dp = Dispatcher(storage=storage)


class QuizStates(StatesGroup):
    QuestionState = State()

class Register(StatesGroup):
    name = State()
    surname = State()
    graduated = State()
    sex = State()
    age = State()
    number = State()

class Edit(StatesGroup):
    name = State()
    surname = State()
    graduated = State()
    sex = State()
    age = State()
    number = State()


async def uuids():
    for _ in range(5):
        uuide = str(uuid.uuid4())
    return uuide

def unique_values(lst):
    return list(set(lst))

async def start_quiz(chat_id, bot, state: FSMContext, questions, item_index):
    if not questions or not isinstance(questions, list):
        await bot.send_message(chat_id, "Произошла ошибка при инициализации вопросов.")
        return

    await state.update_data(questions=questions, question_index=0, item_index=item_index)
    await ask_question(chat_id, bot, state)

async def ask_question(chat_id, bot, state: FSMContext):
    data = await state.get_data()
    questions = data.get('questions')
    question_index = data.get('question_index', 0)
    if questions is None or not isinstance(questions, list):
        await bot.send_message(chat_id, "Произошла ошибка при обработке вопросов.")
        return

    if question_index < len(questions):
        current_question = questions[question_index]
        if current_question['required']:
            if isinstance(current_question, dict):
                if current_question["question_type"] == "checkbox":
                    await kb.send_checkbox_question(chat_id, current_question, bot)
                elif current_question["question_type"] == "radio":
                    await kb.send_radio_question(chat_id, current_question, bot)
                elif current_question["question_type"] == "text":
                    await kb.send_text_question(chat_id, current_question, bot)
            else:
                await bot.send_message(chat_id, "Произошла ошибка при обработке вопроса.")
        else:
            if isinstance(current_question, dict):
                if current_question["question_type"] == "checkbox":
                    await kb.send_checkbox_question_false(chat_id, current_question, bot)
                elif current_question["question_type"] == "radio":
                    await kb.send_radio_question_false(chat_id, current_question, bot)
                elif current_question["question_type"] == "text":
                    await kb.send_text_question_false(chat_id, current_question, bot)
            else:
                await bot.send_message(chat_id, "Произошла ошибка при обработке вопроса.")
        await state.set_state(QuizStates.QuestionState)
    else:
        await bot.send_message(chat_id, "Спасибо за участие в опросе!")
        await state.clear()

@router.message(CommandStart())
async def cmd_start(message: Message):
    js_arr = await db.select_poll()
    arr = prs.parse_json_document(js_arr)
    items = [arr[i]['document_name'] for i in range(len(arr))]
    user_id = await db.search_user_id(message.from_user.id)
    if user_id == message.from_user.id:
        await message.answer('Выберите опрос 📑', reply_markup=kb.create_dynamic_keyboard(items))
    else:
         await message.answer('Привет! Вы не зарегистрированы . Для регистрации нажмите кнопку /register')

@router.callback_query(lambda c: c.data.startswith('next_') or c.data.startswith('prev_'))
async def handle_pagination(callback_query: CallbackQuery):
    js_arr = await db.select_poll()
    arr = prs.parse_json_document(js_arr)
    items = [arr[i]['document_name'] for i in range(len(arr))]
    page = int(callback_query.data.split('_')[1])
    keyboard = kb.create_dynamic_keyboard(items, page=page)
    await callback_query.message.edit_reply_markup(reply_markup=keyboard)
    await callback_query.answer('')

@router.callback_query(lambda c: c.data.startswith('item_'))
async def process_item_callback(callback_query: types.CallbackQuery, state: FSMContext, bot: Bot):
    js_arr = await db.select_poll()
    arr = prs.parse_json_document(js_arr)
    questions = [arr[i]['questions'] for i in range(len(arr))]
    chat_id = callback_query.message.chat.id
    item_index = int(callback_query.data.split('_')[1])
    await state.update_data(answers=[], question_index=0)
    await start_quiz(chat_id, bot, state, questions[item_index], item_index)
    await callback_query.answer('Опрос выбран')

@router.message(QuizStates.QuestionState)
async def process_answer(message: types.Message, state: FSMContext):
    js_arr = await db.select_poll()
    arr = prs.parse_json_document(js_arr)
    docs_id = [arr[i]['doc_id'] for i in range(len(arr))]
    items = [arr[i]['document_name'] for i in range(len(arr))]
    chat_id = message.chat.id
    data = await state.get_data()
    questions = data.get("questions")
    question_index = data.get("question_index", 0)
    answers = data.get("answers", [])
    item_index = data.get("item_index")
    doc_id = docs_id[item_index]
    doc_name = items[item_index]

    if questions is None or not isinstance(questions, list):
        await bot.send_message(chat_id, "Произошла ошибка при обработке вопросов.")
        return
    
    current_question = questions[question_index]
    if message.text != "/skip":
        answers.append({"question": current_question["question_text"], "answer": message.text})
    else:
        answers.append({"question": current_question["question_text"], "answer": []})

    await state.update_data(answers=answers)

    if question_index + 1 < len(questions):
        await state.update_data(question_index=question_index + 1)
        await ask_question(chat_id, bot, state)
    else:
        ans_id = await uuids()
        datas = prs.parse_to_json(ans_id, doc_id, doc_name, answers)
        print(datas)
        await db.set_answer(chat_id, doc_id, str(datas))
        await bot.send_message(chat_id, "Спасибо за участие в опросе!.")
        await state.clear()

@router.callback_query(QuizStates.QuestionState)
async def process_callback(callback_query: types.CallbackQuery, state: FSMContext, bot: Bot):
    js_arr = await db.select_poll()
    arr = prs.parse_json_document(js_arr)
    docs_id = [arr[i]['doc_id'] for i in range(len(arr))]
    items = [arr[i]['document_name'] for i in range(len(arr))]
    chat_id = callback_query.message.chat.id
    data = await state.get_data()
    questions = data.get("questions")
    question_index = data.get("question_index", 0)
    answers = data.get("answers", [])
    confirmed = data.get("confirmed", False)
    selected_options = data.get("selected_options", [])
    item_index = data.get("item_index")
    doc_id = docs_id[item_index]
    doc_name = items[item_index]

    if questions is None or not isinstance(questions, list):
        await bot.send_message(chat_id, "Произошла ошибка при обработке вопросов.")
        return

    current_question = questions[question_index]

    if not isinstance(current_question, dict):
        await bot.send_message(chat_id, "Произошла ошибка при обработке вопроса.")
        return
    
    if current_question["question_type"] == "checkbox" and not confirmed:
        selected_options = [] 

    if current_question["question_type"] in ["checkbox", "radio"]:
        for opt in current_question["options"]:
            option_data = f'{opt["optionText"]}'
            if option_data == callback_query.data:
                if current_question["question_type"] == "radio":
                    selected_options = []
                if option_data not in selected_options:
                    selected_options.append(opt["optionText"])
                await callback_query.answer('Вариант зафиксирован')
        await state.update_data(selected_options=selected_options)
    
    if callback_query.data != "question_false":
        if current_question["question_type"] in ["checkbox", "radio"]:
            if not selected_options:
                await bot.send_message(chat_id, 'Нужно выбрать хотя бы один вариант ответа.')
                return
            await state.update_data(confirmed=True)
        else:
            await bot.send_message(chat_id, 'Нужно выбрать вариант ответа.')
            return
    
    if callback_query.data == "confirm_checkbox" or callback_query.data == "confirm_radio":
        if not confirmed:
            if current_question["question_type"] == "checkbox":
                await kb.send_checkbox_question(chat_id, current_question, bot)
            elif current_question["question_type"] == "radio":
                await kb.send_radio_question(chat_id, current_question, bot)
        else:
            answers.append({"question": current_question["question_text"], "answer": selected_options})
            await state.update_data(confirmed=False)

            if question_index + 1 < len(questions):
                await state.update_data(question_index=question_index + 1)
                await send_next_question(chat_id, bot, state)
            else:
                ans_id = await uuids()
                datas = prs.parse_to_json(ans_id, doc_id, doc_name, answers)
                await db.set_answer(chat_id, doc_id, str(datas))
                await bot.send_message(chat_id, "Спасибо за участие в опросе!")
                await state.clear()
        
    if callback_query.data == "question_false":
        answers.append({"question": current_question["question_text"], "answer": []})
        await state.update_data(answers=answers)
        await state.update_data(confirmed=False)

        if question_index + 1 < len(questions):
            await state.update_data(question_index=question_index + 1)
            await send_next_question(chat_id, bot, state)
        else:
            ans_id = await uuids()
            datas = prs.parse_to_json(ans_id, doc_id, doc_name, answers)
            await db.set_answer(chat_id, doc_id, str(datas))
            await bot.send_message(chat_id, "Спасибо за участие в опросе!")
            await state.clear()
    await callback_query.answer('')

async def send_next_question(chat_id: int, bot: Bot, state: FSMContext):
    data = await state.get_data()
    questions = data.get("questions")
    question_index = data.get("question_index", 0)

    if questions is None or question_index >= len(questions):
        await bot.send_message(chat_id, "Произошла ошибка при получении следующего вопроса.")
        return

    current_question = questions[question_index]
    if current_question["question_type"] == "checkbox" and current_question["required"] == True:
        await kb.send_checkbox_question(chat_id, current_question, bot)
    elif current_question["question_type"] == "radio" and current_question["required"] == True:
        await kb.send_radio_question(chat_id, current_question, bot)
    elif current_question["question_type"] == "text" and current_question["required"] == True:
        await kb.send_text_question(chat_id, current_question, bot)
    elif current_question["question_type"] == "checkbox" and current_question["required"] == False:
        await kb.send_checkbox_question_false(chat_id, current_question, bot)
    elif current_question["question_type"] == "radio" and current_question["required"] == False:
        await kb.send_radio_question_false(chat_id, current_question, bot)
    elif current_question["question_type"] == "text" and current_question["required"] == False:
        await kb.send_text_question_false(chat_id, current_question, bot)


@router.message(Command('register'))
async def register(message: Message, state: FSMContext):
    user_id = await db.search_user_id(message.from_user.id)
    if user_id == message.from_user.id:
        await message.answer('Вы уже зарегистрированы')
    else:
        await state.set_state(Register.name)
        await message.answer('Введите ваше имя')

@router.message(Register.name)
async def register_name(message: Message, state: FSMContext):
    await state.update_data(name=message.text)
    await state.set_state(Register.surname)
    await message.answer('Введите вашу фамилию')

@router.message(Register.surname)
async def register_surname(message: Message, state: FSMContext):
    await state.update_data(surname=message.text)
    await state.set_state(Register.graduated)
    await message.answer('Вы выпускник или студент?',reply_markup=kb.kb_graduated)

@router.message(Register.graduated)
async def register_graduated(message: Message, state: FSMContext):
    await state.update_data(graduated=message.text)
    await state.set_state(Register.sex)
    await message.answer('Введите ваш пол',reply_markup=kb.kb_sex)

@router.message(Register.sex)
async def register_sex(message: Message, state: FSMContext):
    await state.update_data(sex=message.text)
    await state.set_state(Register.age)
    await message.answer('Введите ваш возраст',reply_markup=kb.del_kb)

@router.message(Register.age)
async def register_age(message: Message, state: FSMContext):
    if not message.text.isdigit():
        await message.answer('Пожалуйста, введите только числовое значение для возраста.')
        return

    await state.update_data(age=int(message.text))
    await state.set_state(Register.number)
    await message.answer('Введите ваш номер телефона \nПример: +71234567890')

@router.message(Register.number)
async def register_number(message: Message, state: FSMContext):
    phone_number = re.search(r'^(\+7|8)?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{2}[\s.-]?\d{2}$', message.text)

    if not phone_number:
        await message.answer('Попробуйте снова.')
        return
    await state.update_data(number=message.text)
    data = await state.get_data()
    await db.set_col(message.from_user.id, data["name"],data["surname"], data["age"], data["number"], data["graduated"], data["sex"])
    await message.answer(f'Ваше имя: {data["name"]}\nВаша фамилия: {data["surname"]}\nОбразование: {data["graduated"]}\nВаш возраст: {data["age"]}\nВаш пол: {data["sex"]}\nВаш телефон: {data["number"]}')
    await state.clear()

@router.message(Command('id'))
async def show_user_id(message: Message):
    user_info = await db.show_id(message.from_user.id)
    if user_info:
        name, age, phone_number, surname, graduated, sex = user_info
        await message.answer(f'Ваше имя: {name}\nВаша фамилия: {surname}\nОбразование: {graduated}\nВаш возраст: {age}\nВаш пол: {sex}\nВаш телефон: {phone_number}')
    else:
        await message.answer('Вы не зарегистрированы. Для регистрации нажмите /register')

@router.message(Command('edit'))
async def edit_info(message: Message, state: FSMContext):
    user_info = await db.show_id(message.from_user.id)
    if user_info:
        await state.set_state(Edit.name)
        await message.answer('Введите новое имя (или текущее, если не хотите изменять)')
    else:
        await message.answer('Вы не зарегистрированы. Для регистрации нажмите /register')

@router.message(Edit.name)
async def edit_name(message: Message, state: FSMContext):
    await state.update_data(name=message.text)
    await state.set_state(Edit.surname)
    await message.answer('Введите новую фамилию (или текущую, если не хотите изменять)')

@router.message(Edit.surname)
async def edit_surname(message: Message, state: FSMContext):
    await state.update_data(surname=message.text)
    await state.set_state(Edit.graduated)
    await message.answer('Вы выпускник или студент?',reply_markup=kb.kb_graduated)

@router.message(Edit.graduated)
async def edit_graduated(message: Message, state: FSMContext):
    await state.update_data(graduated=message.text)
    await state.set_state(Edit.sex)
    await message.answer('Введите ваш пол', reply_markup=kb.kb_sex)

@router.message(Edit.sex)
async def edit_sex(message: Message, state: FSMContext):
    await state.update_data(sex=message.text)
    await state.set_state(Edit.age)
    await message.answer('Введите ваш возраст', reply_markup=kb.del_kb)

@router.message(Edit.age)
async def edit_age(message: Message, state: FSMContext):
    if not message.text.isdigit():
        await message.answer('Пожалуйста, введите только числовое значение для возраста.')
        return
    await state.update_data(age=int(message.text))
    await state.set_state(Edit.number)
    await message.answer('Введите новый номер телефона (или текущий, если не хотите изменять)')

@router.message(Edit.number)
async def edit_number(message: Message, state: FSMContext):
    phone_number = re.search(r'^(\+7|8)?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{2}[\s.-]?\d{2}$', message.text)
    
    if not phone_number:
        await message.answer('Попробуйте снова')
        return

    await state.update_data(number=message.text)
    data = await state.get_data()
    await db.update_user_info(message.from_user.id, data["name"], data["age"], data["number"], data["surname"], data["graduated"], data["sex"])
    await message.answer(f'Ваша информация обновлена:\nИмя: {data["name"]}\nВаша фамилия: {data["surname"]}\nВаш возраст: {data["age"]}\nВаш телефон: {data["number"]}\nВаш пол: {data["sex"]}\nОбразование: {data["graduated"]}')